package btb.ui;


import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;

import de.matthiasmann.twl.Alignment;
import de.matthiasmann.twl.Button;
import de.matthiasmann.twl.EditField;
import de.matthiasmann.twl.GUI;
import de.matthiasmann.twl.Label;
import de.matthiasmann.twl.TextArea;
import de.matthiasmann.twl.Widget;
import de.matthiasmann.twl.renderer.lwjgl.LWJGLRenderer;
import de.matthiasmann.twl.textarea.SimpleTextAreaModel;
import de.matthiasmann.twl.theme.ThemeManager;

import btb.engine.CDisplayTask;
import btb.engine.CTaskMessenger;
import btb.util.CGuiUtils;
import btb.util.CUtils;


public class CLoginGui extends Widget
{
	public boolean quit;
	public String logintext;
	
	private static final int DEFAULT_WINDOW_WIDTH = 400;
	private static final int DEFAULT_WINDOW_HEIGHT = 300;
	
	private CDisplayTask callingTask;
	
	private final Label lblTitle;
	private final Label lblUsr;
	private final Label lblPass;
	private final SimpleTextAreaModel txtLogonModel;
	private final TextArea txtLogon;
	private final EditField inputUsername;
	private final EditField inputPassword;
	private final Button btnLogin;
	private final Button btnPlayOffline;
	private final Button btnExit;
	
	protected GUI gui;
	protected ThemeManager theme;
	
	
	public CLoginGui(CDisplayTask _parent)
	{
		this.callingTask = _parent;
		logintext = "Welcome to Beat the Bard. Enter your account\n information and log in, or play offline.";
		
		this.lblTitle = new Label();
		this.lblTitle.setText( "Beat the Bard" );
		this.lblTitle.setTheme( "gamelabel" );
		add( lblTitle );
		
		this.lblUsr = new Label();
		this.lblPass = new Label();
		this.lblUsr.setText( "Username: " );
		this.lblPass.setText( "Password: " );
		this.lblUsr.setTheme( "gamelabel" );
		this.lblPass.setTheme( "gamelabel" );
		add( lblUsr );
		add( lblPass );
		
		//txtLogonInfo = new TextFrame( loginhtml, 2 );
		this.txtLogonModel = new SimpleTextAreaModel();
		this.txtLogon = new TextArea( txtLogonModel );
		this.txtLogonModel.setText( logintext );
		this.txtLogon.setTheme( "gametextarea" );
		add( txtLogon );
		
		this.inputUsername = new EditField();
		this.inputUsername.setTheme( "inputfield" );
		add( inputUsername );
		
		this.inputPassword = new EditField();
		this.inputPassword.setPasswordChar( '*' );
		this.inputPassword.setPasswordMasking( true );
		this.inputPassword.setTheme( "passwordfield" );
		add( inputPassword );
		
		this.btnLogin = new Button();
		this.btnLogin.setTheme( "submitbutton" );
		this.btnLogin.setText( "Login" );
		add( btnLogin );
		
		this.btnExit = new Button();
		this.btnExit.setTheme( "submitbutton" );
		this.btnExit.setText( "Exit" );
		add( btnExit );
		
		this.btnPlayOffline = new Button();
		this.btnPlayOffline.setTheme( "submitbutton" );
		this.btnPlayOffline.setText( "Play Offline" );
		add( btnPlayOffline );
	}
	
	protected void setLayout()
	{
		int x, y, w, h, winW, winH;
		
		winW = Display.getDisplayMode().getWidth();
		winH = Display.getDisplayMode().getHeight();
		
		w = Math.min( 6 * winW / 10, this.lblTitle.getMaxWidth() );
		h = Math.min( 3 * winH / 32, this.lblTitle.getMaxHeight() );
		this.lblTitle.setSize( w, h );
		x = ( winW - this.lblTitle.getWidth() ) / 2;
		y = 2 * winH / 32;
		this.lblTitle.setPosition( x, y );
		this.lblTitle.setAlignment( Alignment.CENTER );
		
		//w = Math.min( 8 * winW / 10, txtLogon.getMaxWidth() );
		//h = Math.min( 8 * winH / 32, txtLogon.getMaxHeight() );
		w = 8 * winW / 10;
		h = 10 * winH / 32;
		this.txtLogon.setSize( w, h );
		x = ( winW - this.txtLogon.getWidth() ) / 2;
		y = 6 * winH / 32;
		this.txtLogon.setPosition( x, y );
		
		//CGuiUtils.println( "w: " + w + ", h: " + h + ", x: " + x + ", y: " + y );
		//CGuiUtils.println( "maxwidth: " + txtLogon.getMaxWidth() + ", maxheight: " + txtLogon.getMaxHeight() );
		
		w = Math.min( 2 * winW / 10, this.lblUsr.getMaxWidth() );
		h = Math.min( 3 * winH / 32, this.lblUsr.getMaxHeight() );
		this.lblUsr.setSize( w, h );
		this.lblPass.setSize( w, h );
		x = ( winW - ( this.lblUsr.getWidth() + this.inputUsername.getWidth() ) ) / 8;
		y = 18 * winH / 32;
		this.lblUsr.setPosition( x, y );
		y = 22 * winH / 32;
		this.lblPass.setPosition( x, y );
		
		w = Math.min( 6 * winW / 10, this.inputUsername.getMaxWidth() );
		h = Math.min( 3 * winH / 32, this.inputUsername.getMaxHeight() );
		this.inputUsername.setSize( w, h );
		this.inputPassword.setSize( w, h );
		x = this.lblUsr.getWidth() + this.lblUsr.getX();
		y = 18 * winH / 32;
		this.inputUsername.setPosition( x, y );
		x = this.lblPass.getWidth() + this.lblPass.getX();
		y = 22 * winH / 32;
		this.inputPassword.setPosition( x, y );
		
		w = Math.min( 8 * winW / 30, this.btnLogin.getMaxWidth() );
		h = Math.min( 3 * winH / 32, this.btnLogin.getMaxHeight() );
		this.btnLogin.setSize( w, h );
		this.btnPlayOffline.setSize( w, h );
		this.btnExit.setSize( w, h );
		
		x = ( winW - ( this.btnLogin.getWidth() * 3 ) ) / 4;
		y = 27 * winH / 32;
		this.btnLogin.setPosition( x, y );
		
		x = 2 * ( winW - ( this.btnPlayOffline.getWidth() * 3 ) ) / 4 + this.btnPlayOffline.getWidth();
		this.btnPlayOffline.setPosition( x, y );
		
		x = 3 * ( winW - ( this.btnExit.getWidth() * 3 ) ) / 4 + ( 2 * this.btnExit.getWidth() );
		this.btnExit.setPosition( x, y );
	}
	
	protected void addCallBacks()
	{
		this.btnLogin.addCallback( new Runnable()
		{	
			public void run()
			{
				String username = CUtils.removeNonAlphanumericChars(inputUsername.getText());
				String password = CUtils.removeNonAlphanumericChars(inputPassword.getText());
				
				if(username.equals("") || password.equals(""))
				{
					txtLogonModel.setText("Either your username or password are blank or were made up entirely of invalid characters.");
					//System.out.println("inputUsername: " + inputUsername.getText() + ", inputPassword: " + inputPassword.getText());
					//System.out.println("Username: " + username + ", Password: " + password);
				}
				else
				{
					btnLogin.setText( "Logging in..." );
					btnLogin.setEnabled( false );
					btnPlayOffline.setEnabled( false );
					
					String ioEventStr = "login%" + username + "%" + password + "%";
					CIOEvent loginEvent = new CIOEvent(this, CIOEvent.CIOE_GUI_EVENT, ioEventStr);
					CTaskMessenger mbox = callingTask.getMailbox();
					mbox.push(CTaskMessenger.TASK_INPUT, loginEvent);
					
					txtLogonModel.setText( "Verifying account credentials..." );
				}
			}
		} );
		
		this.btnPlayOffline.addCallback( new Runnable()
		{
			public void run()
			{
				btnPlayOffline.setText( "Searching..." );
				btnLogin.setEnabled( false );
				btnPlayOffline.setEnabled( false );
				
				String ioEventStr = "playoffline%";
				CIOEvent playOfflineEvent = new CIOEvent(this, CIOEvent.CIOE_GUI_EVENT, ioEventStr);
				CTaskMessenger mbox = callingTask.getMailbox();
				mbox.push(CTaskMessenger.TASK_INPUT, playOfflineEvent);
				
				txtLogonModel.setText( "Searching for other players on the network..." );
			}
		} );
		
		this.btnExit.addCallback( new Runnable()
		{
			public void run()
			{
				txtLogonModel.setText( "Goodbye." );
				
				System.out.println(callingTask.getParentTask().getClass().getName());
				callingTask.getParentTask().kill();
			}
		} );
	}
	
	public void initialize()
	{
		try
		{
			// Start up and initialize LWJGL
			Display.setDisplayMode( new DisplayMode( DEFAULT_WINDOW_WIDTH, DEFAULT_WINDOW_HEIGHT ) );
			Display.create();
			Display.setTitle( "Beat the Bard GUI ProtoType" );
			Display.setVSyncEnabled( true );
			
			// Instantiate a LWJGLRenderer object
			LWJGLRenderer renderer = new LWJGLRenderer();
			
			// In the original sample code this method was the main method, and the class would be instantiated here.
			// ------
			
			// Create GUI object, pass references to main GUI component and LWJGL renderer. In this step, button widget objects are created
			// and added as children to the main GUI component.
			gui = new GUI( this, renderer );
			
			// Create ThemeManager object, pass path to .xml file containing display instructions to its constructor. Also pass the LWJGL renderer.
			// Then, apply the theme to the GUI object.
			
			/** NOTE: Relative file paths start from "workspace/btb_gui_test/bin/btb_gui" - that is, the folder containing the .class files **/
			/** At least, this is true while developing on Portable Eclipse on G:\" **/
			
			String theme_file_path = "../../resource/graphics/btb_theme_02.xml";
			theme = ThemeManager.createThemeManager( CLoginGui.class.getResource( theme_file_path ), renderer );
			gui.applyTheme( theme );
			
			setLayout();
			addCallBacks();
		}
		catch( Exception ex )
		{
			CGuiUtils.errMsg( ex );
		}
	}
	
	public void invoke()
	{
		// Main loop of the GUI component. gui.update() renders the controls using OpenGL, Display.update() tells LWJGL to update the screen.
		// ReduceInputLag tells LWJGL to process messages and poll the mouse and keyboard.
		try
		{
			if( !Display.isCloseRequested() && !this.quit )
			{
				GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);
				
				gui.update();
				Display.update();
				CGuiUtils.reduceInputLag();
			}
		}
		catch( Exception ex )
		{
			CGuiUtils.errMsg(ex);
		}
	}
	
	public void dismiss()
	{
		try
		{
			this.gui.destroy();
			this.theme.destroy();
			Display.destroy();
		}
		catch( Exception ex )
		{
			CGuiUtils.errMsg(ex);
		}
	}
}
